/**
 * @widoc $.swipeCtrl
 * @namespace comp
 * @depends eventHelper/$.eventHelper, styleHelper/$.styleHelper
 * @des 滑动显示操作按钮
 * @param {object} el
 * @param {object} opts
 * @param {boolean=} opts.brotherDom 滑动显示的操作按钮与 swipeEl 是否为兄弟节点，默认为 false。
 * @param {object|string} opts.swipeEl 监听滑动事件的元素或选择器。
 * @param {number=} opts.duration 动画延迟时间，单位 ms，默认为 100。注意与 css 中 .wi-swipectrl-item 定义的过渡延时一致。
 * @param {number=} opts.ctrlWidth 滑动显示的操作按钮宽度，默认为 80。
 * @param {string=} opts.ctrlUnit ctrlWidth 的单位，默认为 'px'。
 * @param {boolean=} opts.allowMultiple 是否允许多个操作元素显示，默认为 false，即 el 中滑出操作元素时，其中其他操作元素将隐藏。
 * @param {string=} opts.direction 滑动方向：'left'|'right'，默认为 'left'。
 * @return {object} obj
 * @rtn {function} obj.fSwipeOpen(dom) 显示指定 dom 对应的操作元素
 * @rtn {function} obj.fSwipeClose(dom) 隐藏指定 dom 对应的操作元素
 * @rtn {function} obj.fReset()
 */
$.swipeCtrl = function(el, opts){
    opts = $.extend({
        brotherDom: false,// 滑动显示的操作按钮与 swipeEl 是否为兄弟节点
        swipeEl: '',// 监听滑动事件的元素或选择器
        duration: 100,// 注意与 css 中 .wi-swipectrl-item 定义的过渡延时一直
        ctrlWidth: 80,// 滑动显示的操作按钮宽度
        ctrlUnit: 'px',// ctrlWidth 的单位
        allowMultiple: false,// 是否允许多个操作元素显示，false 时，el 中滑出操作元素时，会将其他项的操作元素隐藏
        direction: 'left'// 滑动方向：'left'|'right'
    }, opts);
    var api;
    var jqsSwipe;// 所有滑动元素
    var sTransEndEvent = $.eventHelper.transformEndEvent,// 过渡结束事件类型
        fGetEventAttr = $.eventHelper.fGetEventAttr,
        sTransitionName = $.styleHelper.translateName('transition');
    var bMoving = false;
    var oStartStat = null,// touchStart 时记录状态
        nTouchesDiff,// 手指滑动的位移
        nTranslateX = 0,
        dTouch;// 正在被滑动的 dom
    var sSwipeBase = '',// 滑动基线：'hor', 'ver', ''
        sDirection = opts.direction,
        bBrotherCtrl = opts.brotherDom,
        nSwipeDuration = Number(opts.duration / 1000) || 100;
    var nCtrlWidth = opts.ctrlWidth,
        sCtrlUnit = opts.ctrlUnit;
    // 显示指定 dom 对应的操作元素
    var fSwipeOpen = function(dom){
        var el;
        if(dom){
            if(dom instanceof jQuery){
                el = dom;
                dom = el.get(0);
            }
            else{
                el = $(dom);
            }
        }
        else{
            return;
        }
        var h = 0,
            i = false;
        var k = function(e){
            el.off(sTransEndEvent);
            i = true;
            k = null;
            h++;
            if(h > 1){
                return
            }
            el.attr('data-lock', 'true');
        };
        dom.style.WebkitTransform = dom.style.transform
            = 'translateX(' + (opts.direction === 'left' ? -nCtrlWidth : nCtrlWidth) + sCtrlUnit + ') ';
        dom.style.webkitTransitionDuration = dom.style.transitionDuration = nSwipeDuration + 's';
        el.on(sTransEndEvent, k);
        setTimeout(function(){
            if(i){
                return
            }
            k()
        }, parseInt(nSwipeDuration + 25, 10));
    };
    // 隐藏指定 dom 对应的操作元素
    var fSwipeClose = function(dom){
        var el;
        if(dom){
            if(dom instanceof jQuery){
                el = dom;
                dom = el.get(0);
            }
            else{
                el = $(dom);
            }
        }
        else{
            return;
        }
        var d = false,
            i = 0;
        var j = function(e){
            el.off(sTransEndEvent);
            d = true;
            j = null;
            i++;
            if(i > 1){
                return
            }
            el.attr('data-lock', 'false');
        };
        dom.style.WebkitTransform = dom.style.transform = 'translateX(-' + 0 + sCtrlUnit + ') ';
        dom.style.webkitTransitionDuration = dom.style.transitionDuration = nSwipeDuration + 's';
        el.on(sTransEndEvent, j);
        setTimeout(function(){
            if(d){
                return
            }
            j()
        }, parseInt(nSwipeDuration + 25, 10));
    };
    var fOnTouchStart = function(e){
        var jqTouch = $(this);
        var touchPoint = fGetEventAttr(e, 'targetTouches')[0];
        if(!opts.allowMultiple){
            jqsSwipe.filter('[data-lock="true"]').each(function(i, dom){
                if(!jqTouch.is(dom)){
                    fSwipeClose(dom)
                }
            })
        }
        bMoving = false;
        sSwipeBase = '';
        oStartStat = {
            x: touchPoint.pageX || touchPoint.clientX,
            y: touchPoint.pageY || touchPoint.clientY,
            startTime: +new Date
        };
        dTouch = jqTouch.get(0);
        jqTouch.css(sTransitionName + 'Duration', '0s');
        nTranslateX = (dTouch.style.WebkitTransform.replace(/translateX\(/g, "").replace(/(px|rem|%)\)/g, "")) * 1
            || (dTouch.style.transform.replace(/translateX\(/g, "").replace(/(px|rem|%)\)/g, "")) * 1
            || 0;
        jqTouch.on('touchmove', fOnTouchMove);
        jqTouch.on('touchend', fOnTouchEnd);
    };
    var fOnTouchMove = function(e){
        if(sSwipeBase === 'ver'
            || fGetEventAttr(e, 'targetTouches').length > 1
            || e.scale && e.scale !== 1){
            return;
        }
        var touchPoint = fGetEventAttr(e, 'changedTouches')[0];
        var x = touchPoint.pageX || touchPoint.clientX,
            y = touchPoint.pageY || touchPoint.clientY;
        var l, touchDir;
        if(sSwipeBase === ''){// 判断滑动基线
            touchDir = $.eventHelper.fGetMoveDirection(oStartStat.x, oStartStat.y, x, y);
            if(touchDir[2]){
                sSwipeBase = '';
            }
            else if(touchDir[0] === 'u' || touchDir[0] === 'd'){
                sSwipeBase = 'ver';
                return
            }
            else{
                sSwipeBase = 'hor';
            }
        }
        //e.preventDefault();
        nTouchesDiff = x - oStartStat.x + nTranslateX;
        bMoving = true;
        if(sDirection == 'left'){
            if(nTouchesDiff >= 0){
                dTouch.style.WebkitTransform = dTouch.style.transform = 'translateX(-' + 0 + sCtrlUnit + ') translateZ(0)'
            }
            else{
                l = Math.abs(nTouchesDiff);
                dTouch.style.WebkitTransform = dTouch.style.transform = 'translateX(' + -l + sCtrlUnit + ') translateZ(0)';
                if(l > nCtrlWidth){
                    if(bBrotherCtrl){
                        l = (nCtrlWidth + (l - nCtrlWidth) * 0.39)
                    }
                    else{
                        l = nCtrlWidth
                    }
                    dTouch.style.WebkitTransform = dTouch.style.transform = 'translateX(' + -l + sCtrlUnit + ') translateZ(0)'
                }
            }
        }
        if(sDirection == 'right'){
            if(nTouchesDiff >= 0){
                l = Math.abs(nTouchesDiff);
                dTouch.style.WebkitTransform = dTouch.style.transform = 'translateX(' + l + sCtrlUnit + ') translateZ(0)';
                if(l > nCtrlWidth){
                    if(bBrotherCtrl){
                        l = (nCtrlWidth + (l - nCtrlWidth) * 0.39)
                    }
                    else{
                        l = nCtrlWidth
                    }
                    dTouch.style.WebkitTransform = dTouch.style.transform = 'translateX(' + l + sCtrlUnit + ' ) translateZ(0)'
                }
            }
            else{
                dTouch.style.WebkitTransform = dTouch.style.transform = 'translateX(-' + 0 + sCtrlUnit + ') translateZ(0)'
            }
        }
    };
    var fOnTouchEnd = function(e){
        if(sSwipeBase === 'ver' || !bMoving){
            return
        }
        var nDiffTime = (+new Date) - oStartStat.startTime;
        var ctrlWidth = opts.ctrlWidth;
        var direction = opts.direction;
        var touchesDiff = nTouchesDiff;
        var bLocked = dTouch.getAttribute('data-lock') === 'true';// jqCtrl 是否显示，显示时 el 被锁定
        // 快速滑动时，直接操作；慢速滑动时，根据实际滑动位移判断打开还是关闭
        if(nDiffTime < 300
            && ( touchesDiff < -10 && direction === 'left' || touchesDiff > 10 && direction === 'right')
            || nDiffTime > 300
            && ( touchesDiff < -parseInt(ctrlWidth / 3, 10) && direction === 'left' || touchesDiff > parseInt(ctrlWidth / 3, 10) && direction === 'right')){
            if(bLocked){
                fSwipeClose(dTouch, opts);
                //e.preventDefault()
            }
            else{
                fSwipeOpen(dTouch, opts)
            }
        }
        else{
            fSwipeClose(dTouch, opts);
            //e.preventDefault()
        }
    };

    var fReset = function(){
        jqsSwipe = el.find(opts.swipeEl);
        jqsSwipe.addClass('wi-swipectrl-item')
                .attr('data-lock', 'false');// jqCtrl 显示时，锁定 el，data-lock = 'true'
    };

    var fInit = function(){
        el.on('touchstart.swipectrl', opts.swipeEl, fOnTouchStart);
        fReset();
    };
    api = {
        fSwipeOpen: fSwipeOpen,
        fSwipeClose: fSwipeClose,
        fReset: fReset
    };
    fInit();
    return api;
};
